package cn.hicard.core;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;



/**
 * 数据库操作泛型基类
 * @author zhangy
 *
 * @param <T>
 */
public class CoreDao<T> extends HibernateDaoSupport {
	
	/**
	 * 默认的构造函数，通过反射取得当前泛型的具体类，使用方便
	 */
	public CoreDao(){}
	
	/**
	 * 通过当前泛型的具体类型的Class来构造，高效万无一失，推荐使用
	 * @param clsT
	 */
	public CoreDao(Class<T> clsT){
		entityClass = clsT;
	}
	
	private Class<T> entityClass;
	
	/**
	 * 取得泛型实体类名
	 * @return
	 * @throws Exception
	 */
	private Class<T> getEntityClass() {
		if (entityClass == null) {
			Type type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
			entityClass = (Class<T>) type;
		}
		return entityClass;
	}
	
	/**
	 * 跟据主键查询单个实体
	 * @param pk
	 * @return
	 * @throws Exception
	 */
	public T getByPk(Serializable pk) throws Exception{
		return getHibernateTemplate().get(getEntityClass(), pk);
	}
	
	/**
	 * 查询实体所有数据集合，请慎用，<font color="red"><b>当心卡死</b></font>
	 * @return
	 * @throws Exception
	 */
	public List<T> getAll() throws Exception{
		String className = getEntityClass().getName();
		String entiyName = className.substring(className.lastIndexOf(".") + 1);
		String hql = "FROM " + entiyName;
		return findByHql(hql);
	}
	
	/**
	 * 保存或更新单个实体
	 * @param entity
	 */
	public void saveOrUpdate(T entity)throws Exception {
		getHibernateTemplate().saveOrUpdate(entity);
	}
	
	/**
	 * 保存或更新实体集合
	 * @param entities
	 * @throws Exception
	 */
	public void saveOrUpdate(List<T> entities) throws Exception{		
		getHibernateTemplate().saveOrUpdateAll(entities);
	}
	
	/**
	 * 保存实体
	 * @param entity
	 * @throws Exception
	 */
	public void save(T entity) throws Exception{
		getHibernateTemplate().save(entity);
	}
	
	/**
	 * 批量保存实体集合
	 * @param entities
	 * @throws Exception
	 */
	public void save(final List<T> entities) throws Exception{
		getHibernateTemplate().execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) throws HibernateException,
					SQLException {				
				for (int i = 0; i < entities.size(); i++) {
					session.save(entities.get(i));
				}
				return null;
			}
			
		});
	}
	
	/**
	 * 更新实体，如果T的主键为空或主键对应的实体不存在则会抛出异常
	 * @param entity
	 * @throws Exception
	 */
	public void update(T entity) throws Exception{
		getHibernateTemplate().update(entity);
	}
	
	/**
	 * 更新实体集合，请注意，集合中的每一个实体T的主键必须存在
	 * @param entities
	 * @throws Exception
	 */
	public void update(final List<T> entities) throws Exception{		
		getHibernateTemplate().execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) throws HibernateException,
					SQLException {
				for (int i = 0; i < entities.size(); i++) {
					session.update(entities.get(i));
				}
				return null;
			}
		});
	}
	
	/**
	 * 通过HQL语句大容量更新，适用于一条(update/delete)语句更新或删除多条记录
	 * @param hql
	 * @param params
	 * @throws Exception
	 */
	public void updateByHqlBulk(String hql, Object...params) throws Exception{
		getHibernateTemplate().bulkUpdate(hql, params);
	}
	
	/**
	 * 通过SQL语句大容量更新，适用于一条(update/delete)语句更新或删除多条记录
	 * @param sql
	 * @param params
	 * @throws Exception
	 */
	public void updateBySqlBulk(final String sql, final Object... params) throws Exception{		 
		getHibernateTemplate().execute(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.executeUpdate();
			}			
		});
	}

	/**
	 * 跟据主键删除实体
	 * @param id
	 * @throws Exception
	 */
	public void delete(Serializable id) throws Exception{
		T item = getByPk(id);
		if(item != null){
			getHibernateTemplate().delete(item);
		}
	}

	
	/**
	 * 使用HQL统计数量
	 * @param hql
	 * @param params
	 * @return
	 */
	public int findCountByHql(String hql, Object... params)throws Exception{
		List list = getHibernateTemplate().find(hql, params);	
		if(list != null && list.size()>0){
			return Integer.parseInt(list.get(0).toString());
		}else{
			return 0;
		}
	}


	/**
	 * 根据HQL查询<b> [实体] </b>集合，实例类型为确定的T
	 * @param hql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<T> findByHql(String hql, Object... params)throws Exception{
		return getHibernateTemplate().find(hql, params);
	}
	
	
	/**
	 * HQL分页查询，反回一页集的集合T
	 * @param hql
	 * @param page
	 * @param parms
	 * @return
	 */
	public List<T> findByHqlPage(final String hql, final Page page, final Object... parms) throws Exception{
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(page.getSize() * page.getIndex());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < parms.length; i++) {
					query.setParameter(i, parms[i]);
				}
				return query.list();
			}			
		});
	}

	
	/**
	 * 根据HQL查询<b> [字段] </b>集合，不建议用于查询具体的实例对象<br/>
	 * 这个方法用于执行HQL语句中SELECT中含有独立字段的HQL语句<br/>
	 * <p>
	 * <b> 适合 </b>用于类似这样写HQL的查询：“SELECT 字段1, 字段2,... FROM 对象 ...”<br/>
	 * <b> 不建议 </b>用于样写HQL的查询：“FROM 对象 ...”或 “SELECT obj FROM 对象 AS obj ...”，
	 * 这种情况请使用findByHql方法代替
	 * </p>
	 * <p>
	 * A.如果SELECT的字段只有1个，则查返回的类型为List&ltObject&gt<br/>
	 * B.如果SELECT的字段数量大于1个，则结果为List&ltObject[]&gt型
	 * </p>
	 * @param hql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List findFieldsByHql(String hql, Object... params)throws Exception{
		return getHibernateTemplate().find(hql, params);
	}
	

	/**
	 * 根据SQL查询<b> [字段] </b>集合，返回结果中字段的顺序与SQL中的顺序一致<br/>
	 * <p>
	 * A.如果SELECT的字段只有1个，则查返回的类型为List&ltObject&gt<br/>
	 * B.如果SELECT的字段数量大于1个，则结果为List&ltObject[]&gt型
	 * </p>
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List findFieldsByHqlPage(final String hql, final Page page, final Object... params) throws Exception{
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(page.getIndex() * page.getSize());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}
			
		});
	}

	

	/**
	 * 使用SQL查询，结果返回查询字段与值的Map映射集合
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, Object>> findMapByHql(final String hql, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);				
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
	
	/**
	 * 使用HQL查询分页，结果返回查询字段与值的Map映射集合
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, Object>> findMapByHqlPage(final String hql, final Page page, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);		
				query.setFirstResult(page.getIndex() * page.getSize());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
	
	/**
	 * 使用SQL统计数量
	 * @param hql
	 * @param params
	 * @return
	 */
	public int findCountBySql(String sql, Object... params)throws Exception{	
		List list = findFieldsBySql(sql, params);
		if(list != null && list.size()>0){
			return Integer.parseInt(list.get(0).toString());
		}else{
			return 0;
		}
	}

	/**
	 * 通过SQL查询实体，反回集合T，只有当实体T的字段与SELECT的字段与对象属性完全一致时才可使用本方法<br/>
	 * 此功能由Hibernate提供实现，SELECT目标表的所有字段，能用*的建议用*代替
	 * @param sql
	 * @param page
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<T> findBySql(final String sql, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				// 这里指定实例对象的Class返回的结果就是具体的对象面不是Object[]
				Query query = session.createSQLQuery(sql).setResultTransformer(Transformers.aliasToBean(getEntityClass()));
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
		
	/**
	 * 通过SQL查询实体，反回一页的集合T，只有当实体T的字段与SELECT的字段与对象属性完全一致时才可使用本方法<br/>
	 * 此功能由Hibernate提供实现，SELECT目标表的所有字段，能用*的建议用*代替
	 * @param sql
	 * @param page
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<T> findBySqlPage(final String sql, final Page page, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				// 这里指定实例对象的Class返回的结果就是具体的对象面不是Object[]
				Query query = session.createSQLQuery(sql).setResultTransformer(Transformers.aliasToBean(getEntityClass()));
				query.setFirstResult(page.getIndex() * page.getSize());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
	

	/**
	 * 根据SQL查询<b> [字段] </b>集合，返回结果中字段的顺序与SQL中的顺序一致<br/>
	 * <p>
	 * A.如果SELECT的字段只有1个，则查返回的类型为List&ltObject&gt<br/>
	 * B.如果SELECT的字段数量大于1个，则结果为List&ltObject[]&gt型
	 * </p>
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List findFieldsBySql(final String sql, final Object... params) throws Exception{
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}
			
		});
	}

	
	/**
	 * 根据SQL查询<b> [字段] </b>集合，返回反回一页，结果中字段的顺序与SQL中的顺序一致<br/>
	 * <p>
	 * A.如果SELECT的字段只有1个，则查返回的类型为List&ltObject&gt<br/>
	 * B.如果SELECT的字段数量大于1个，则结果为List&ltObject[]&gt型
	 * </p>
	 * @param sql
	 * @param page
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List findFieldsBySqlPage(final String sql, final Page page, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				query.setFirstResult(page.getIndex() * page.getSize());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}

	/**
	 * 使用SQL查询，结果返回查询字段与值的Map映射集合
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, Object>> findMapBySql(final String sql, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);				
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
	
	/**
	 * 使用SQL查询分页，结果返回查询字段与值的Map映射集合
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, Object>> findMapBySqlPage(final String sql, final Page page, final Object... params) throws Exception{		
		return 
		getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);		
				query.setFirstResult(page.getIndex() * page.getSize());
				query.setMaxResults(page.getSize());
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i]);
				}
				return query.list();
			}			
		});
	}
}
